/*
 * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
 *
 * https://www.mall4j.com/
 *
 * 未经允许，不可做商业用途！
 *
 * 版权所有，侵权必究！
 */
package com.yami.shop.service.impl;

import cn.binarywang.wx.miniapp.bean.WxMaTemplateData;
import cn.binarywang.wx.miniapp.bean.WxMaUniformMessage;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yami.shop.bean.enums.RemindType;
import com.yami.shop.bean.enums.SendType;
import com.yami.shop.bean.model.NotifyLog;
import com.yami.shop.bean.param.NotifyTemplateParam;
import com.yami.shop.bean.param.OrderParam;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.util.Json;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.config.ShopConfig;
import com.yami.shop.config.WxConfig;
import com.yami.shop.dao.NotifyLogMapper;
import com.yami.shop.service.NotifyLogService;
import com.yami.shop.service.SmsLogService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author lhd
 * @date 2020-07-01 15:44:27
 */
@Slf4j
@Service
@AllArgsConstructor
public class NotifyLogServiceImpl extends ServiceImpl<NotifyLogMapper, NotifyLog> implements NotifyLogService {

    private final NotifyLogMapper notifyLogMapper;
    private final SmsLogService smsLogService;
    private final ShopConfig shopConfig;
    private final WxConfig wxConfig;
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public IPage<NotifyLog> pageByParam(PageParam<NotifyLog> page, OrderParam orderParam) {
        IPage<NotifyLog> notifyLogIpage = notifyLogMapper.pageByParam(page, orderParam);
        for (NotifyLog record : notifyLogIpage.getRecords()) {
            if (Objects.equals(record.getSendType(), 0)) {
                record.setShopName("平台");
            }
        }
        return notifyLogIpage;
    }

    @Override
    public Integer countMsgNum(String orderNumber) {
        return notifyLogMapper.countMsgNum(orderNumber);
    }

    @Override
    public void sendMessage(List<NotifyLog> logList) {
        for (NotifyLog notifyLog : logList) {
            if (StrUtil.isBlank(notifyLog.getUserMobile()) || StrUtil.isBlank(notifyLog.getParamContent())) {
                continue;
            }
            NotifyTemplateParam param = Json.parseObject(notifyLog.getParamContent(), NotifyTemplateParam.class);
            // 获取对应map
            Map<String, String> smsParam = getSmsParam(param);
            try {
                // 推送短信和公众号消息
                if (Objects.equals(notifyLog.getRemindType(), RemindType.SMS.value())) {
                    smsLogService.sendMsgSms(notifyLog.getTemplateCode(), param.getUserMobile(), smsParam);
                }
                if (Objects.equals(notifyLog.getRemindType(), RemindType.MP.value()) && StrUtil.isNotBlank(param.getOpenId())) {
                    sendMpMessage(notifyLog.getMpCode(), param);
                }
            } catch (Exception e) {
                log.error(SendType.LAUNCH_REFUND.getDesc() + "：消息推送失败！");
            }
        }
    }

    @Override
    public List<NotifyLog> listUnSendMsgList() {
        return notifyLogMapper.listUnSendMsgList();
    }

    @Override
    public Integer countUnreadMsg(String userId) {
        // 未读系统消息数量
        int countUnreadSysMsg = count(new LambdaQueryWrapper<NotifyLog>()
                .eq(NotifyLog::getRemindId, userId)
                .eq(NotifyLog::getStatus, 0)
                .lt(NotifyLog::getSendType, 100)
                .eq(NotifyLog::getRemindType, 3));
        // 未读客服消息数量
        int countUnreadCsMsg = notifyLogMapper.countUnreadCsMsg(userId) == null ? 0 : notifyLogMapper.countUnreadCsMsg(userId);

        return countUnreadSysMsg + countUnreadCsMsg;
    }


    /**
     * 发送微信模板信息
     */
    private void sendMpMessage(String mpCode, NotifyTemplateParam param) {
        if (StrUtil.isBlank(param.getUserId())) {
            return;
        }
        WxMaUniformMessage wxMaUniformMessage = new WxMaUniformMessage();
        wxMaUniformMessage.setMpTemplateMsg(true);
        wxMaUniformMessage.setToUser(param.getOpenId());
        wxMaUniformMessage.setAppid(shopConfig.getWxMp().getAppId());
        //公众号模板消息所要跳转的小程序
        WxMaUniformMessage.MiniProgram miniProgram = new WxMaUniformMessage.MiniProgram();
        miniProgram.setAppid(shopConfig.getWxMiniApp().getAppId());
        miniProgram.setPagePath("pages/user/user");
        wxMaUniformMessage.setMiniProgram(miniProgram);
        //模板id
        wxMaUniformMessage.setTemplateId(mpCode);
        //模板数据集合
        wxMaUniformMessage.setData(getWxMaTemplateDataList(param, param.getShopName()));
        try {
            wxConfig.getWxMaService().getMsgService().sendUniformMsg(wxMaUniformMessage);
        } catch (WxErrorException e) {
            //用户未关注公众号，导致的消息发送失败异常
            if (Objects.nonNull(e) && Objects.nonNull(e.getError()) && e.getError().getErrorCode() == 43004) {
                logger.info("用户（" + param.getUserId() + "）没有关注公众号，导致消息发送失败");
            }
            //其他异常
            else {
                log.error("WxErrorException:", e);
            }
        }
    }


    private List<WxMaTemplateData> getWxMaTemplateDataList(NotifyTemplateParam param, String shopName) {
        Map<Integer, List<WxMaTemplateData>> mpMap = new HashMap<>(24);
        List<WxMaTemplateData> dataList = new ArrayList<>();
        String priceStr = param.getPrice() + "元";
        payMsg(param, mpMap, dataList, priceStr);

        refundMsg(param, shopName, mpMap, priceStr);

        deliveryMsg(param, mpMap, priceStr);

        groupMsg(param, mpMap, priceStr);

        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "会员升级通知"));
        dataList.add(new WxMaTemplateData("keyword1", param.getLevelName()));
        dataList.add(new WxMaTemplateData("keyword2", "成功！"));
        dataList.add(new WxMaTemplateData("remark", "感谢您的支持！"));
        mpMap.put(SendType.MEMBER.getValue(), dataList);

        return mpMap.get(param.getSendType());
    }

    private void groupMsg(NotifyTemplateParam param, Map<Integer, List<WxMaTemplateData>> mpMap, String priceStr) {
        List<WxMaTemplateData> dataList;
        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "您参加的拼团因为有效期内未成团，我们将在3个工作日内为您安排自动退款"));
        dataList.add(new WxMaTemplateData("keyword1", param.getProdName()));
        dataList.add(new WxMaTemplateData("keyword2", priceStr));
        dataList.add(new WxMaTemplateData("keyword3", "商城"));
        dataList.add(new WxMaTemplateData("remark", "点击进入订单详情页，查看退款进度！"));
        mpMap.put(SendType.GROUP_FAIL.getValue(), dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "恭喜你，拼团已经成功！"));
        dataList.add(new WxMaTemplateData("keyword1", param.getProdName()));
        dataList.add(new WxMaTemplateData("keyword2", priceStr));
        dataList.add(new WxMaTemplateData("remark", "请登录商城，查看订单发货信息"));
        mpMap.put(SendType.GROUP_SUCCESS.getValue(), dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "恭喜你，开团已经成功！"));
        dataList.add(new WxMaTemplateData("keyword1", param.getProdName()));
        dataList.add(new WxMaTemplateData("keyword2", priceStr));
        dataList.add(new WxMaTemplateData("remark", "快去小程序将参团链接分享给好友进行参团吧！"));
        mpMap.put(SendType.GROUP_START.getValue(), dataList);
    }

    private void deliveryMsg(NotifyTemplateParam param, Map<Integer, List<WxMaTemplateData>> mpMap, String priceStr) {
        List<WxMaTemplateData> dataList;
        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "尊敬的客户，您的订单提货成功啦。"));
        dataList.add(new WxMaTemplateData("keyword1", param.getProdName()));
        dataList.add(new WxMaTemplateData("keyword2", priceStr));
        dataList.add(new WxMaTemplateData("keyword3", param.getProdNum().toString()));
        dataList.add(new WxMaTemplateData("keyword4", DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN)));
        dataList.add(new WxMaTemplateData("remark", "商城感谢您的支持！"));
        mpMap.put(SendType.WRITE_OFF.getValue(), dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "亲，物流显示您的订单买家已经确认收货！"));
        dataList.add(new WxMaTemplateData("keyword1", param.getOrderNumber()));
        dataList.add(new WxMaTemplateData("keyword2", param.getProdName()));
        dataList.add(new WxMaTemplateData("keyword3", "已确认收货"));
        dataList.add(new WxMaTemplateData("remark", "如有疑问请及时与客服联系！"));
        mpMap.put(SendType.RECEIPT_ORDER.getValue(), dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "你的买家已退货，请及时处理"));
        dataList.add(new WxMaTemplateData("keyword1", param.getOrderNumber()));
        dataList.add(new WxMaTemplateData("keyword2", param.getRemark()));
        dataList.add(new WxMaTemplateData("remark", "如有疑问请及时与客服联系！"));
        mpMap.put(SendType.RETURN_REFUND.getValue(), dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "商品已在送往客官的路上"));
        dataList.add(new WxMaTemplateData("keyword1", param.getProdName()));
        dataList.add(new WxMaTemplateData("keyword2", "已发货"));
        dataList.add(new WxMaTemplateData("keyword3", param.getDvyName()));
        dataList.add(new WxMaTemplateData("keyword4", param.getDvyFlowId()));
        dataList.add(new WxMaTemplateData("remark", DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN)));
        mpMap.put(SendType.DELIVERY.getValue(), dataList);
    }

    private void refundMsg(NotifyTemplateParam param, String shopName, Map<Integer, List<WxMaTemplateData>> mpMap, String priceStr) {
        List<WxMaTemplateData> dataList;
        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "您的退款申请商家已同意"));
        dataList.add(new WxMaTemplateData("keyword1", param.getOrderNumber()));
        dataList.add(new WxMaTemplateData("keyword2", param.getProdName()));
        dataList.add(new WxMaTemplateData("keyword3", priceStr));
        dataList.add(new WxMaTemplateData("remark", "请及时登录商城，查看退款信息"));
        mpMap.put(SendType.AGREE_REFUND.getValue(), dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "你的退款申请被商家驳回，可与商家协商沟通"));
        dataList.add(new WxMaTemplateData("keyword1", param.getOrderNumber()));
        dataList.add(new WxMaTemplateData("keyword2", priceStr));
        dataList.add(new WxMaTemplateData("keyword3", param.getRejectMessage()));
        dataList.add(new WxMaTemplateData("remark", "请及时登录商城，查看退款信息"));
        mpMap.put(SendType.REFUSE_REFUND.getValue(), dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "您有退款单即将超时，请及时联系商家处理"));
        dataList.add(new WxMaTemplateData("keyword1", shopName));
        dataList.add(new WxMaTemplateData("keyword2", "1笔"));
        dataList.add(new WxMaTemplateData("remark", "如有疑问请及时与客服联系！"));
        mpMap.put(SendType.REFUND_OUT_TIME.getValue(), dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "店铺有新的退款申请，请及时处理"));
        dataList.add(new WxMaTemplateData("keyword1", priceStr));
        dataList.add(new WxMaTemplateData("keyword2", param.getRejectMessage()));
        dataList.add(new WxMaTemplateData("keyword3", DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN)));
        dataList.add(new WxMaTemplateData("keyword4", "退款金额原路返回"));
        dataList.add(new WxMaTemplateData("keyword5", param.getRemark()));
        dataList.add(new WxMaTemplateData("remark", "请您尽快请登录商家后台操作处理。"));
        mpMap.put(SendType.LAUNCH_REFUND.getValue(), dataList);
    }

    private void payMsg(NotifyTemplateParam param, Map<Integer, List<WxMaTemplateData>> mpMap, List<WxMaTemplateData> dataList, String priceStr) {
        String firstData = "亲爱的" + param.getNickName() + ",您在商城购买的宝贝还未付款哦！为确保您心爱的宝贝早日启程、顺利抵达，记得尽早付款哦！";
        dataList.add(new WxMaTemplateData("first", firstData));
        dataList.add(new WxMaTemplateData("keyword1", param.getOrderNumber()));
        dataList.add(new WxMaTemplateData("keyword2", DateUtil.format(param.getCreateTime(), DatePattern.NORM_DATETIME_PATTERN)));
        dataList.add(new WxMaTemplateData("keyword3", param.getProdName()));
        dataList.add(new WxMaTemplateData("remark", "请您及时付款以免订单过期。"));
        mpMap.put(SendType.PRESS_PAY.getValue(), dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "你好，你的订单已付款成功。"));
        dataList.add(new WxMaTemplateData("keyword1", param.getOrderNumber()));
        dataList.add(new WxMaTemplateData("keyword2", param.getProdName()));
        dataList.add(new WxMaTemplateData("keyword3", DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN)));
        dataList.add(new WxMaTemplateData("keyword4", priceStr));
        dataList.add(new WxMaTemplateData("remark", "感谢您的支持！"));
        mpMap.put(SendType.PAY_SUCCESS.getValue(), dataList);
    }

    private Map<String, String> getSmsParam(NotifyTemplateParam param) {
        Map<String, String> smsParam = new HashMap<>(20);
        smsParam.put("orderNumber", param.getOrderNumber());
        smsParam.put("shopName", param.getShopName());
        smsParam.put("prodName", param.getProdName());
        if (StrUtil.isBlank(param.getNickName())) {
            smsParam.put("nickName", "用户");
        } else {
            smsParam.put("nickName", param.getNickName());
        }
        smsParam.put("levelName", param.getLevelName());
        smsParam.put("cancelTime", param.getCancelTime());
        smsParam.put("price", String.valueOf(param.getPrice()));
        smsParam.put("dvyFlowId", param.getDvyFlowId());
        smsParam.put("stationName", param.getStationName());
        smsParam.put("dvyName", param.getDvyName());
        smsParam.put("dvyTime", DateUtil.format(param.getDvyTime(),
                DatePattern.NORM_DATETIME_PATTERN));
        smsParam.put("day", String.valueOf(Constant.MAX_REFUND_APPLY_TIME));
        smsParam.put("hour", param.getHour().toString());
        smsParam.put("date", DateUtil.format(param.getDvyTime(),
                DatePattern.NORM_DATETIME_PATTERN));
        return smsParam;
    }
}
